<template>
    <f7-sheet swipe-to-close swipe-handler=".swipe-handler" class="numpad-sheet" style="height: auto"
              :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
        <div class="swipe-handler"></div>
        <f7-page-content class="margin-top no-padding-top">
            <div class="margin-top padding-horizontal" v-if="hint">
                <span>{{ hint }}</span>
            </div>
            <div class="numpad-values" @click="paste">
                <span class="numpad-value" :class="currentDisplayNumClass">{{ currentDisplay }}</span>
            </div>
            <div class="numpad-buttons">
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(7)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[7] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(8)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[8] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(9)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[9] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('×')">
                    <span class="numpad-button-text numpad-button-text-normal">&times;</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(4)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[4] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(5)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[5] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(6)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[6] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('−')">
                    <span class="numpad-button-text numpad-button-text-normal">&minus;</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(1)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[1] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(2)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[2] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(3)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[3] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('+')">
                    <span class="numpad-button-text numpad-button-text-normal">&plus;</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" v-if="supportDecimalSeparator" @click="inputDecimalSeparator()">
                    <span class="numpad-button-text numpad-button-text-normal">{{ decimalSeparator }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" v-if="!supportDecimalSeparator" @click="inputDoubleNum(0)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ `${digits[0]}${digits[0]}` }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="inputNum(0)">
                    <span class="numpad-button-text numpad-button-text-normal">{{ digits[0] }}</span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-num" @click="backspace" @taphold="clear()">
                <span class="numpad-button-text numpad-button-text-normal">
                    <f7-icon class="icon-with-direction" f7="delete_left"></f7-icon>
                </span>
                </f7-button>
                <f7-button class="numpad-button numpad-button-confirm no-right-border no-bottom-border" fill @click="confirm()">
                    <span :class="{ 'numpad-button-text': true, 'numpad-button-text-confirm': !currentSymbol }">{{ confirmText }}</span>
                </f7-button>
            </div>
        </f7-page-content>
    </f7-sheet>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue';

import { useI18n } from '@/locales/helpers.ts';
import { useI18nUIComponents, isiOS } from '@/lib/ui/mobile.ts';

import { NumeralSystem } from '@/core/numeral.ts';
import { ALL_CURRENCIES } from '@/consts/currency.ts';
import { isNumber } from '@/lib/common.ts';
import logger from '@/lib/logger.ts';

const props = defineProps<{
    modelValue: number;
    minValue?: number;
    maxValue?: number;
    currency?: string;
    flipNegative?: boolean;
    hint?: string;
    show: boolean;
}>();

const emit = defineEmits<{
    (e: 'update:modelValue', value: number): void;
    (e: 'update:show', value: boolean): void;
}>();

const {
    tt,
    getAllLocalizedDigits,
    getCurrentNumeralSystemType,
    getCurrentDecimalSeparator,
    parseAmountFromLocalizedNumerals,
    parseAmountFromWesternArabicNumerals,
    formatAmountToWesternArabicNumeralsWithoutDigitGrouping,
    appendDigitGroupingSymbolAndDecimalSeparator
} = useI18n();
const { showToast } = useI18nUIComponents();

const isSupportClipboard = !!navigator.clipboard;

const previousValue = ref<string>('');
const currentSymbol = ref<string>('');
const currentValue = ref<string>(getInitedStringValue(props.modelValue, props.flipNegative));
const pasteingAmount = ref<boolean>(false);

const numeralSystem = computed<NumeralSystem>(() => getCurrentNumeralSystemType());

const digits = computed<string[]>(() => getAllLocalizedDigits());
const decimalSeparator = computed<string>(() => getCurrentDecimalSeparator());

const supportDecimalSeparator = computed<boolean>(() => {
    if (!props.currency || !ALL_CURRENCIES[props.currency] || !isNumber(ALL_CURRENCIES[props.currency]!.fraction)) {
        return true;
    }

    return (ALL_CURRENCIES[props.currency]!.fraction as number) > 0;
});

const currentDisplay = computed<string>(() => {
    const finalPreviousValue = appendDigitGroupingSymbolAndDecimalSeparator(numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(previousValue.value));
    let finalCurrentValue = currentValue.value;
    let currentValueSuffix = '';

    if (finalCurrentValue && finalCurrentValue[finalCurrentValue.length - 1] === decimalSeparator.value) {
        finalCurrentValue = finalCurrentValue.substring(0, finalCurrentValue.length - 1);
        currentValueSuffix = decimalSeparator.value;
    }

    finalCurrentValue = appendDigitGroupingSymbolAndDecimalSeparator(numeralSystem.value.replaceWesternArabicDigitsToLocalizedDigits(finalCurrentValue));

    if (currentValueSuffix) {
        finalCurrentValue += currentValueSuffix;
    }

    if (currentSymbol.value) {
        return `${finalPreviousValue} ${currentSymbol.value} ${finalCurrentValue}`;
    } else {
        return finalCurrentValue;
    }
});

const currentDisplayNumClass = computed<string>(() => {
    if (currentDisplay.value && currentDisplay.value.length >= 24) {
        return 'numpad-value-small';
    } else if (currentDisplay.value && currentDisplay.value.length >= 16) {
        return 'numpad-value-normal';
    } else {
        return 'numpad-value-large';
    }
});

const confirmText = computed<string>(() => {
    if (currentSymbol.value) {
        return '=';
    } else {
        return tt('OK');
    }
});

function getInitedStringValue(value: number, flipNegative?: boolean): string {
    if (flipNegative) {
        value = -value;
    }

    return getStringValue(value, true);
}

function getStringValue(value: number, hideZero: boolean): string {
    if (!isNumber(value)) {
        return '';
    }

    const textualNumber = formatAmountToWesternArabicNumeralsWithoutDigitGrouping(value, props.currency);

    const decimalSeparator = getCurrentDecimalSeparator();
    const decimalSeparatorPos = textualNumber.indexOf(decimalSeparator);

    if (decimalSeparatorPos < 0) {
        if (hideZero && textualNumber === NumeralSystem.WesternArabicNumerals.digitZero) {
            return '';
        }

        return textualNumber;
    }

    const integer = textualNumber.substring(0, decimalSeparatorPos);
    const decimals = textualNumber.substring(decimalSeparatorPos + 1, textualNumber.length);
    let newDecimals = '';

    for (let i = decimals.length - 1; i >= 0; i--) {
        if (decimals[i] !== NumeralSystem.WesternArabicNumerals.digitZero || newDecimals.length > 0) {
            newDecimals = decimals[i] + newDecimals;
        }
    }

    if (newDecimals.length < 1) {
        if (hideZero && integer === NumeralSystem.WesternArabicNumerals.digitZero) {
            return '';
        }

        return integer;
    }

    return `${integer}${decimalSeparator}${newDecimals}`;
}

function inputNum(num: number): void {
    if (!previousValue.value && currentSymbol.value === '−') {
        currentValue.value = '-' + currentValue.value;
        currentSymbol.value = '';
    }

    if (currentValue.value === NumeralSystem.WesternArabicNumerals.digitZero) {
        currentValue.value = num.toString();
        return;
    } else if (currentValue.value === `-${NumeralSystem.WesternArabicNumerals.digitZero}`) {
        currentValue.value = '-' + num.toString();
        return;
    }

    const decimalSeparatorPos = currentValue.value.indexOf(decimalSeparator.value);

    if (decimalSeparatorPos >= 0 && currentValue.value.substring(decimalSeparatorPos + 1, currentValue.value.length).length >= 2) {
        return;
    }

    const newValue = currentValue.value + num.toString();

    if (isNumber(props.minValue)) {
        const current = parseAmountFromWesternArabicNumerals(newValue);

        if (current < (props.minValue)) {
            return;
        }
    }

    if (isNumber(props.maxValue)) {
        const current = parseAmountFromWesternArabicNumerals(newValue);

        if (current > (props.maxValue)) {
            return;
        }
    }

    currentValue.value = newValue;
}

function inputDoubleNum(num: number): void {
    inputNum(num);
    inputNum(num);
}

function inputDecimalSeparator(): void {
    if (currentValue.value.indexOf(decimalSeparator.value) >= 0) {
        return;
    }

    if (!previousValue.value && currentSymbol.value === '−') {
        currentValue.value = '-' + currentValue.value;
        currentSymbol.value = '';
    }

    if (currentValue.value.length < 1) {
        currentValue.value = NumeralSystem.WesternArabicNumerals.digitZero;
    } else if (currentValue.value === '-') {
        currentValue.value = '-' + NumeralSystem.WesternArabicNumerals.digitZero;
    }

    currentValue.value = currentValue.value + decimalSeparator.value;
}

function setSymbol(symbol: string): void {
    if (currentValue.value) {
        if (currentSymbol.value) {
            const lastFormulaCalcResult = confirm();

            if (!lastFormulaCalcResult) {
                return;
            }
        }

        previousValue.value = currentValue.value;
        currentValue.value = '';
    }

    currentSymbol.value = symbol;
}

function backspace(): void {
    if (!currentValue.value || currentValue.value.length < 1) {
        if (currentSymbol.value) {
            currentValue.value = previousValue.value;
            previousValue.value = '';
            currentSymbol.value = '';
        }

        return;
    }

    currentValue.value = currentValue.value.substring(0, currentValue.value.length - 1);
}

function clear(): void {
    currentValue.value = '';
    previousValue.value = '';
    currentSymbol.value = '';
}

function paste(): void {
    if (!isiOS() || !isSupportClipboard || pasteingAmount.value) {
        pasteingAmount.value = false;
        return;
    }

    pasteingAmount.value = true;

    navigator.clipboard.readText().then(text => {
        pasteingAmount.value = false;

        if (!text) {
            return;
        }

        const parsedAmount = parseAmountFromLocalizedNumerals(text);

        if (Number.isNaN(parsedAmount) || !Number.isFinite(parsedAmount)) {
            showToast('Cannot parse amount from clipboard');
            return;
        }

        if (isNumber(props.minValue)) {
            if (parsedAmount < (props.minValue)) {
                showToast('Numeric Overflow');
                return;
            }
        }

        if (isNumber(props.maxValue)) {
            if (parsedAmount > (props.maxValue)) {
                showToast('Numeric Overflow');
                return;
            }
        }

        currentValue.value = getStringValue(parsedAmount, false);
    }).catch(error => {
        logger.error('failed to read clipboard text', error);
    });
}

function confirm(): boolean {
    if (currentSymbol.value && currentValue.value.length >= 1) {
        const previous = parseAmountFromWesternArabicNumerals(previousValue.value);
        const current = parseAmountFromWesternArabicNumerals(currentValue.value);
        let finalValue = 0;

        switch (currentSymbol.value) {
            case '+':
                finalValue = previous + current;
                break;
            case '−':
                finalValue = previous - current;
                break;
            case '×':
                finalValue = Math.trunc(previous * current / 100);
                break;
            default:
                finalValue = previous;
        }

        if (isNumber(props.minValue)) {
            if (finalValue < (props.minValue)) {
                showToast('Numeric Overflow');
                return false;
            }
        }

        if (isNumber(props.maxValue)) {
            if (finalValue > (props.maxValue)) {
                showToast('Numeric Overflow');
                return false;
            }
        }

        currentValue.value = getStringValue(finalValue, false);
        previousValue.value = '';
        currentSymbol.value = '';

        return true;
    } else if (currentSymbol.value && currentValue.value.length < 1) {
        currentValue.value = previousValue.value;
        previousValue.value = '';
        currentSymbol.value = '';

        return true;
    } else {
        let value: number = parseAmountFromWesternArabicNumerals(currentValue.value);

        if (props.flipNegative) {
            value = -value;
        }

        emit('update:modelValue', value);
        close();

        return true;
    }
}

function close(): void {
    emit('update:show', false);
}

function onSheetOpen(): void {
    currentValue.value = getInitedStringValue(props.modelValue, props.flipNegative);
    previousValue.value = '';
    currentSymbol.value = '';
}

function onSheetClosed(): void {
    close();
}

watch(() => props.flipNegative, (newValue) => {
    currentValue.value = getInitedStringValue(props.modelValue, newValue);
});
</script>

<style>
.numpad-sheet {
    height: auto;
}

.numpad-values {
    border-bottom: 1px solid var(--f7-page-bg-color);
}

.numpad-value {
    display: flex;
    position: relative;
    padding-inline-start: 16px;
    line-height: 1;
    height: var(--ebk-numpad-value-height);
    align-items: center;
    box-sizing: border-box;
    user-select: none;
}

.numpad-value-small {
    font-size: var(--ebk-numpad-value-small-font-size);
}

.numpad-value-normal {
    font-size: var(--ebk-numpad-value-normal-font-size);
}

.numpad-value-large {
    font-size: var(--ebk-numpad-value-large-font-size);
}

.numpad-buttons {
    display: flex;
    flex-wrap: wrap;
}

.numpad-button {
    display: flex;
    position: relative;
    text-align: center;
    border-radius: 0;
    border-right: 1px solid var(--f7-page-bg-color);
    border-bottom: 1px solid var(--f7-page-bg-color);
    height: 60px;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    box-sizing: border-box;
    user-select: none;
    touch-action: none;
}

.numpad-button-num {
    width: calc(80% / 3);
}

.numpad-button-function, .numpad-button-confirm {
    width: 20%;
}

.numpad-button-num.active-state, .numpad-button-function.active-state {
    background-color: rgba(var(--f7-color-black-rgb), .15);
}

.numpad-button-text {
    display: block;
    font-size: var(--ebk-numpad-normal-button-font-size);
    font-weight: normal;
    line-height: 1;
}

.numpad-button-text-normal {
    color: var(--f7-color-black);
}

.dark .numpad-button-text-normal {
    color: var(--f7-color-white);
}

.numpad-button-text-confirm {
    font-size: var(--ebk-numpad-confirm-button-font-size);
}
</style>
